﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Workflows.Components.TextMining.Collapse
{
    /// <summary>
    /// 
    /// </summary>
    public class FuzzyIntegerComparer:IAttributeComparer
    {
        #region Implementation of IAttributeComparer

        /// <summary>
        /// specify either use code snippet or class
        /// </summary>
        public AttributeComparerType ComparerType
        {
            get { return AttributeComparerType.ClassComparer; }
        }

        /// <summary>
        /// 
        /// </summary>
        public SqlDbType FieldDbType
        {
            get { return SqlDbType.Int; }
            set { throw new System.NotImplementedException(); }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value1"></param>
        /// <param name="value2"></param>
        /// <param name="penalty"></param>
        /// <param name="conn"></param>
        /// <param name="unevenDistTableName"></param>
        /// <returns></returns>
        public double Compare(object value1, object value2, double penalty, SqlConnection conn, string unevenDistTableName)
        {
            if (value1 == null || value1 == DBNull.Value)
                return 0;
            if (value2 == null || value2 == DBNull.Value)
                return 0;
            int number1 = 0;
            bool canParse1 = int.TryParse(value1.ToString(), out number1);
            if (!canParse1)
            {
                canParse1 = int.TryParse(this.RemoveNonDigitCharacters(value1.ToString()), out number1);
                if (!canParse1)
                    return 0;
            }
            int number2 = 0;
            bool canParse2 = int.TryParse(value2.ToString(), out number2);
            if (!canParse2)
            {
                canParse2 = int.TryParse(this.RemoveNonDigitCharacters(value2.ToString()), out number2);
                if (!canParse2)
                    return 0;
            }
            if (number1 == number2)
                return 1;
            if(number1.ToString().Length != number2.ToString().Length)
            {
                // off by one digit 
                if(Math.Abs(number1.ToString().Length - number2.ToString().Length)==1)
                {
                    if (number1.ToString().StartsWith(number2.ToString()) ||
                        number2.ToString().StartsWith(number1.ToString()))
                        return 0.3;
                    else
                        return penalty;
                }
                else
                {
                    return penalty;
                }
            }
            else
            {
                if (number1 - number2 == 1 || number2 - number1 == 1)
                    return 0.75;
                char[] digits1 = number1.ToString().ToCharArray();
                char[] digits2 = number2.ToString().ToCharArray();
                int digitsThatAreDifferent = 0;
                for(int i=0;i<digits1.Length;i++)
                {
                    if (digits1[i] != digits2[i])
                        digitsThatAreDifferent++;
                }
                if(digitsThatAreDifferent==1)
                    return 1.0 - ((double) digitsThatAreDifferent)/digits1.Length;
                else
                    return penalty;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="values"></param>
        /// <param name="conn"></param>
        /// <param name="unevenDistTableName"></param>
        /// <returns></returns>
        public object Merge(List<object> values, SqlConnection conn, string unevenDistTableName)
        {
            object mode = null;
            int maxFreq = 0;
            Dictionary<object,int> freqs=new Dictionary<object, int>();
            foreach(object val in values)
            {
                if(val==null || val.ToString().Length==0)
                    continue;

                if (freqs.ContainsKey(val))
                    freqs[val] = freqs[val] + 1;
                else 
                    freqs.Add(val, 1);
            }
            foreach(object val in freqs.Keys)
            {
                if(freqs[val]>maxFreq)
                {
                    maxFreq = freqs[val];
                    mode = val;
                }
            }
            return mode;
        }


        private string RemoveNonDigitCharacters(string input)
        {
            string pattern = @"[^\d]";
            input = Regex.Replace(input, pattern, "");
            return input;
        }
        #endregion
    }
}
